// -*-mode:c++; coding:utf-8-*-

#ifndef _XBASE_SYNC_HANDLER_HPP_
#define _XBASE_SYNC_HANDLER_HPP_

#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <boost/thread/mutex.hpp>

#include "scan_struct.hpp"

namespace xbase
{
	// 注意：对状态 m_is_locked 的修改必须要在持有锁的时候进行，否
	// 则会出现BUG。
	struct sync_handler
	{
		sync_handler()
			: m_mutex()
			, m_is_locked(false) {
			m_mutex.lock();
			m_is_locked = true;
		}
		
		~sync_handler() {
			if(m_is_locked)
			{
				m_is_locked = false;
				m_mutex.unlock();
			}
		}
		
		void notify() {
			m_is_locked = false;
			m_mutex.unlock();
		}
		
		void wait() {
			m_mutex.lock();
			m_is_locked = true;
		}
		
		// void timed_wait() {
		// }
		
		boost::mutex m_mutex;
		bool m_is_locked;
	};

	// 
	// 若要扩展参数个数，只需在这里的模板参数列表中增加，并实现相应的特例化即可。
	// 

	template<typename Arg1 = void, typename Arg2 = void, typename Arg3 = void,
		 typename Arg4 = void, typename Arg5 = void, typename Arg6 = void
		 /* ... */>
	struct basic_sync_handler;

#define __alias__(argN, name)				\
	argN##_type &get_##name() {			\
		return m_##argN;			\
	}

	// 
	// 特例化，分别对应不同个数的参数
	// 

	template<>
	struct basic_sync_handler<>
		: public sync_handler
	{
		typedef basic_sync_handler<> this_type;
		typedef boost::system::error_code error_code;
		typedef boost::function<void(const error_code&)> handler_type;

		typedef void result_type;
		typedef error_code arg1_type;

		void operator()(const arg1_type &arg1) {
			m_arg1 = arg1;
			this->notify();
		}

		handler_type make_handler() {
			return boost::bind(&this_type::operator(),
					   this, _1);
		}

		arg1_type m_arg1;

		__alias__(arg1, error_code)
	};

	template<typename Arg1>
	struct basic_sync_handler<Arg1>
		: public sync_handler
	{
		typedef basic_sync_handler<Arg1> this_type;
		typedef boost::system::error_code error_code;
		typedef boost::function<void(Arg1, const error_code&)> handler_type;

		typedef void result_type;
		typedef Arg1 arg1_type;
		typedef error_code arg2_type;

		void operator()(arg1_type arg1,
				const arg2_type &arg2) {
			m_arg1 = arg1;
			m_arg2 = arg2;
			this->notify();
		}

		handler_type make_handler() {
			return boost::bind(&this_type::operator(),
					   this, _1, _2);
		}

		arg1_type m_arg1;
		arg2_type m_arg2;

		__alias__(arg1, row_result_ptr)
		__alias__(arg1, meta_row_result_ptr)
		__alias__(arg1, succ_row_count)
		__alias__(arg1, table_info)
		__alias__(arg2, error_code)
	};

	template<typename Arg1, typename Arg2>
	struct basic_sync_handler<Arg1, Arg2>
		: public sync_handler
	{
		typedef basic_sync_handler<Arg1, Arg2> this_type;
		typedef boost::system::error_code error_code;
		typedef boost::function<void(Arg1, Arg2, const error_code&)> handler_type;

		typedef void result_type;
		typedef Arg1 arg1_type;
		typedef Arg2 arg2_type;
		typedef error_code arg3_type;

		void operator()(arg1_type arg1,
				arg2_type arg2,
				const arg3_type &arg3) {
			m_arg1 = arg1;
			m_arg2 = arg2;
			m_arg3 = arg3;
			this->notify();
		}

		handler_type make_handler() {
			return boost::bind(&this_type::operator(),
					   this,
					   _1, _2, _3);
		}

		arg1_type m_arg1;
		arg2_type m_arg2;
		arg3_type m_arg3;

		__alias__(arg1, tablet_info)
		__alias__(arg2, server_address)
		__alias__(arg3, error_code)
	};

	template<typename Arg1, typename Arg2, typename Arg3>
	struct basic_sync_handler<Arg1, Arg2, Arg3>
		: public sync_handler
	{
		typedef basic_sync_handler<Arg1, Arg2, Arg3> this_type;
		typedef boost::system::error_code error_code;
		typedef boost::function<void(Arg1, Arg2, Arg3,
					     const error_code&)> handler_type;

		typedef void result_type;
		typedef Arg1 arg1_type;
		typedef Arg2 arg2_type;
		typedef Arg3 arg3_type;
		typedef error_code arg4_type;

		void operator()(arg1_type arg1,
				arg2_type arg2,
				arg3_type arg3,
				const arg4_type &arg4) {
			m_arg1 = arg1;
			m_arg2 = arg2;
			m_arg3 = arg3;
			m_arg4 = arg4;
			this->notify();
		}

		handler_type make_handler() {
			return boost::bind(&this_type::operator(),
					   this,
					   _1, _2, _3,
					   _4);
		}

		arg1_type m_arg1;
		arg2_type m_arg2;
		arg3_type m_arg3;
		arg4_type m_arg4;

		__alias__(arg4, error_code)
	};

	template<typename Arg1, typename Arg2, typename Arg3,
		 typename Arg4>
	struct basic_sync_handler<Arg1, Arg2, Arg3,
				  Arg4>
		: public sync_handler
	{
		typedef basic_sync_handler<Arg1, Arg2, Arg3,
					   Arg4> this_type;
		typedef boost::system::error_code error_code;
		typedef boost::function<void(Arg1, Arg2, Arg3,
					     Arg4,
					     const error_code&)> handler_type;

		typedef void result_type;
		typedef Arg1 arg1_type;
		typedef Arg2 arg2_type;
		typedef Arg3 arg3_type;
		typedef Arg4 arg4_type;
		typedef error_code arg5_type;

		void operator()(arg1_type arg1,
				arg2_type arg2,
				arg3_type arg3,
				arg4_type arg4,
				const arg5_type &arg5) {
			m_arg1 = arg1;
			m_arg2 = arg2;
			m_arg3 = arg3;
			m_arg4 = arg4;
			m_arg5 = arg5;
			this->notify();
		}

		handler_type make_handler() {
			return boost::bind(&this_type::operator(),
					   this,
					   _1, _2, _3,
					   _4, _5);
		}

		arg1_type m_arg1;
		arg2_type m_arg2;
		arg3_type m_arg3;
		arg4_type m_arg4;
		arg5_type m_arg5;

		__alias__(arg5, error_code)
	};

	template<typename Arg1, typename Arg2, typename Arg3,
		 typename Arg4, typename Arg5>
	struct basic_sync_handler<Arg1, Arg2, Arg3,
				  Arg4, Arg5>
		: public sync_handler
	{
		typedef basic_sync_handler<Arg1, Arg2, Arg3,
					   Arg4, Arg5> this_type;
		typedef boost::system::error_code error_code;
		typedef boost::function<void(Arg1, Arg2, Arg3,
					     Arg4, Arg5,
					     const error_code&)> handler_type;

		typedef void result_type;
		typedef Arg1 arg1_type;
		typedef Arg2 arg2_type;
		typedef Arg3 arg3_type;
		typedef Arg4 arg4_type;
		typedef Arg5 arg5_type;
		typedef error_code arg6_type;

		void operator()(arg1_type arg1,
				arg2_type arg2,
				arg3_type arg3,
				arg4_type arg4,
				arg5_type arg5,
				const arg6_type &arg6) {
			m_arg1 = arg1;
			m_arg2 = arg2;
			m_arg3 = arg3;
			m_arg4 = arg4;
			m_arg5 = arg5;
			m_arg6 = arg6;
			this->notify();
		}

		handler_type make_handler() {
			return boost::bind(&this_type::operator(),
					   this,
					   _1, _2, _3,
					   _4, _5, _6);
		}
		
		arg1_type m_arg1;
		arg2_type m_arg2;
		arg3_type m_arg3;
		arg4_type m_arg4;
		arg5_type m_arg5;
		arg6_type m_arg6;

		__alias__(arg6, error_code)
	};

#undef __alias__

} // namespace xbase

#endif	// _XBASE_SYNC_HANDLER_HPP_
